﻿//// - Schnelles Verschieben zwischen Monitoren mit unterschiedlicher Auflösung führt zum relativen Verschieben der Maus zum Fenster
//// - Aero-snap auf falschen monitor (immer 2) bei stark üerlappendem fenster und monitor 2 größer als / gleich groß wie monitor 1

//using System;
//using System.ComponentModel;
//using System.Runtime.InteropServices;
//using System.Windows;
//using System.Windows.Controls;
//using System.Windows.Controls.Primitives;
//using System.Windows.Input;
//using System.Windows.Interop;
//using System.Windows.Media;

//using advadev.Windows.CustomWindows.WindowsGDI;


//namespace advadev.Windows.CustomWindows
//{

//    /// <summary>
//    /// Represents a custom window
//    /// </summary>
//    [TemplatePart(Name = "PART_CloseButton", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_MaximizeButton", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_MinimizeButton", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_DragMoveArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_LeftResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_LeftTopResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_TopResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_RightTopResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_RightResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_RightBottomResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_BottomResizeArea", Type = typeof(UIElement))]
//    [TemplatePart(Name = "PART_LeftBottomResizeArea", Type = typeof(UIElement))]
//    public class CustomWindow : Window
//    {

//        /// <summary>for internal use</summary>
//        private UIElement _closeButton;
//        /// <summary>for internal use</summary>
//        private UIElement _maximizeButton;
//        /// <summary>for internal use</summary>
//        private UIElement _minimizeButton;
//        /// <summary>for internal use</summary>
//        private UIElement _dragMoveArea;
//        /// <summary>for internal use</summary>
//        private UIElement _leftResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _leftTopResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _topResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _rightTopResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _rightResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _rightBottomResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _bottomResizeArea;
//        /// <summary>for internal use</summary>
//        private UIElement _leftBottomResizeArea;
//        /// <summary>for internal use</summary>
//        private double _calculatedMaxHeight;
//        /// <summary>for internal use</summary>
//        private double _calculatedMaxWidth;
//        /// <summary>for internal use</summary>
//        private double _userDefinedMaxHeight;
//        /// <summary>for internal use</summary>
//        private double _userDefinedMaxWidth;
//        /// <summary>for internal use</summary>
//        private double _restoreLeft;
//        /// <summary>for internal use</summary>
//        private double _restoreTop;


//        /// <summary>
//        /// Initializes the CustomWindow class
//        /// </summary>
//        static CustomWindow()
//        {
//            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomWindow), new FrameworkPropertyMetadata(typeof(CustomWindow)));
//            CloseCommand = new RoutedUICommand();
//            MaximizeCommand = new RoutedUICommand();
//            MinimizeCommand = new RoutedUICommand();
//            NormalizeCommand = new RoutedUICommand();
//            SwapWindowStateCommand = new RoutedUICommand();
//        }

//        /// <summary>
//        /// Initializes a new instance of the CustomWindow class
//        /// </summary>
//        public CustomWindow()
//        {
//            AllowsTransparency = true;
//            WindowStyle = WindowStyle.None;
//            SourceInitialized += new EventHandler((object sender, EventArgs e) =>
//            {
//                try
//                {
//                    HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).AddHook(new HwndSourceHook(windowProc));
//                }
//                catch { }
//            });
//            CommandBindings.Add(new CommandBinding(CloseCommand, new ExecutedRoutedEventHandler((object sender, ExecutedRoutedEventArgs args) =>
//            {
//                Close();
//            }), new CanExecuteRoutedEventHandler((object sender, CanExecuteRoutedEventArgs args) =>
//            {
//                args.CanExecute = true;
//            })));
//            CommandBindings.Add(new CommandBinding(MaximizeCommand, new ExecutedRoutedEventHandler((object sender, ExecutedRoutedEventArgs args) =>
//            {
//                WindowState = WindowState.Maximized;
//            }), new CanExecuteRoutedEventHandler((object sender, CanExecuteRoutedEventArgs args) =>
//            {
//                args.CanExecute = (ResizeMode == ResizeMode.CanResize);
//            })));
//            CommandBindings.Add(new CommandBinding(MinimizeCommand, new ExecutedRoutedEventHandler((object sender, ExecutedRoutedEventArgs args) =>
//            {
//                WindowState = WindowState.Minimized;
//            }), new CanExecuteRoutedEventHandler((object sender, CanExecuteRoutedEventArgs args) =>
//            {
//                args.CanExecute = true;
//            })));
//            CommandBindings.Add(new CommandBinding(NormalizeCommand, new ExecutedRoutedEventHandler((object sender, ExecutedRoutedEventArgs args) =>
//            {
//                WindowState = WindowState.Normal;
//            }), new CanExecuteRoutedEventHandler((object sender, CanExecuteRoutedEventArgs args) =>
//            {
//                args.CanExecute = (ResizeMode == ResizeMode.CanResize);
//            })));
//            CommandBindings.Add(new CommandBinding(SwapWindowStateCommand, new ExecutedRoutedEventHandler((object sender, ExecutedRoutedEventArgs args) =>
//            {
//                WindowState = (WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized);
//            }), new CanExecuteRoutedEventHandler((object sender, CanExecuteRoutedEventArgs args) =>
//            {
//                args.CanExecute = (ResizeMode == ResizeMode.CanResize);
//            })));
//            // -->> ISSUE #0003 (Part 1)
//            // Description: Wrong window size in monitor 2 if monitor 2 is bigger than monitor 1
//            // Steps to reproduce:
//            // (1) Attach a second monitor
//            // (2) Set screen resolution of monitor 2 to a bigger value than for monitor 1
//            // (3) Maximize the window in monitor 2
//            // Resulting problem: Maximized window has the wrong size (the window is too big)
//            // Solution: Use MaxHeight and MaxWidth and limit the window size by that values (but
//            //           use those values only if the window is maximized and then use the minimum
//            //           of the values calculated during the getminmaxinfo method and the user
//            //           defined values)
//            //ensureMaxScreenSizeSetting();
//            // <<-- ISSUE
//            // -->> ISSUE #0004
//            // Description: Aero-snap of a window overlapping between two monitors maximizes with
//            //              wrong size (sometimes)
//            // Steps to reproduce:
//            // (1) Attach a second monitor with a different (e.g. lower) resolution than monitor 1
//            // (2) Drag a window on the left side of the window drag area
//            // (3) Raise the aero-snap with mouse in monitor 1 and maximum of the window in monitor 2
//            // Resulting problem: Aero-snap snaps to corrent monitor (monitor 1) but with the wrong
//            //                    size (size of monitor 2)
//            // Solution: Minimize window and reposition it temporary to left top edge of the monitor
//            //           with the mouse in to force recalculation of the minmaxinfo and re-maximize
//            //           the window
//            ensureMaximizedMonitor();
//            // <<-- ISSUE
//        }


//        /// <summary>
//        /// Gets the close command
//        /// </summary>
//        static public RoutedUICommand CloseCommand
//        {
//            get;
//            private set;
//        }

//        /// <summary>
//        /// Gets the maximize command
//        /// </summary>
//        static public RoutedUICommand MaximizeCommand
//        {
//            get;
//            private set;
//        }

//        /// <summary>
//        /// Gets the minimize command
//        /// </summary>
//        static public RoutedUICommand MinimizeCommand
//        {
//            get;
//            private set;
//        }

//        /// <summary>
//        /// Gets the normalize command
//        /// </summary>
//        static public RoutedUICommand NormalizeCommand
//        {
//            get;
//            private set;
//        }

//        /// <summary>
//        /// Gets the swap window state command
//        /// </summary>
//        static public RoutedUICommand SwapWindowStateCommand
//        {
//            get;
//            private set;
//        }


//        /// <summary>
//        /// Applies the template
//        /// </summary>
//        override public void OnApplyTemplate()
//        {
//            base.OnApplyTemplate();
//            if (_dragMoveArea != null)
//            {
//                //_dragMoveArea.MouseMove -= dragMoveArea_MouseMove;
//                //_dragMoveArea.MouseLeftButtonDown -= dragMoveArea_MouseLeftButtonDown;
//                _dragMoveArea = null;
//            }
//            if (_leftResizeArea != null)
//            {
//                //_leftResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _leftResizeArea = null;
//            }
//            if (_leftTopResizeArea != null)
//            {
//                //_leftTopResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _leftTopResizeArea = null;
//            }
//            if (_topResizeArea != null)
//            {
//                //_topResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _topResizeArea = null;
//            }
//            if (_rightTopResizeArea != null)
//            {
//                //_rightTopResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _rightTopResizeArea = null;
//            }
//            if (_rightResizeArea != null)
//            {
//                //_rightResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _rightResizeArea = null;
//            }
//            if (_rightBottomResizeArea != null)
//            {
//                //_rightBottomResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _rightBottomResizeArea = null;
//            }
//            if (_bottomResizeArea != null)
//            {
//                //_bottomResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _bottomResizeArea = null;
//            }
//            if (_leftBottomResizeArea != null)
//            {
//                //_leftBottomResizeArea.PreviewMouseLeftButtonDown -= resizeArea_PreviewMouseLeftButtonDown;
//                _leftBottomResizeArea = null;
//            }
//            if (Template != null)
//            {
//                _closeButton = Template.FindName("PART_CloseButton", this) as UIElement;
//                _maximizeButton = Template.FindName("PART_MaximizeButton", this) as UIElement;
//                _minimizeButton = Template.FindName("PART_MinimizeButton", this) as UIElement;
//                _dragMoveArea = Template.FindName("PART_DragMoveArea", this) as UIElement;
//                if (_dragMoveArea != null)
//                {
//                    //_dragMoveArea.MouseLeftButtonDown += dragMoveArea_MouseLeftButtonDown;
//                    //_dragMoveArea.MouseMove += dragMoveArea_MouseMove;
//                }
//                _leftResizeArea = Template.FindName("PART_LeftResizeArea", this) as UIElement;
//                if (_leftResizeArea != null)
//                {
//                    //_leftResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _leftTopResizeArea = Template.FindName("PART_LeftTopResizeArea", this) as UIElement;
//                if (_leftTopResizeArea != null)
//                {
//                    //_leftTopResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _topResizeArea = Template.FindName("PART_TopResizeArea", this) as UIElement;
//                if (_topResizeArea != null)
//                {
//                    //_topResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _rightTopResizeArea = Template.FindName("PART_RightTopResizeArea", this) as UIElement;
//                if (_rightTopResizeArea != null)
//                {
//                    //_rightTopResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _rightResizeArea = Template.FindName("PART_RightResizeArea", this) as UIElement;
//                if (_rightResizeArea != null)
//                {
//                    //_rightResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _rightBottomResizeArea = Template.FindName("PART_RightBottomResizeArea", this) as UIElement;
//                if (_rightBottomResizeArea != null)
//                {
//                    //_rightBottomResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _bottomResizeArea = Template.FindName("PART_BottomResizeArea", this) as UIElement;
//                if (_bottomResizeArea != null)
//                {
//                    //_bottomResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//                _leftBottomResizeArea = Template.FindName("PART_LeftBottomResizeArea", this) as UIElement;
//                if (_leftBottomResizeArea != null)
//                {
//                    //_leftBottomResizeArea.PreviewMouseLeftButtonDown += resizeArea_PreviewMouseLeftButtonDown;
//                }
//            }
//        }

//        ///// <summary>
//        ///// Handles the "MouseLeftButtonDown" event of the drag move area
//        ///// </summary>
//        ///// <param name="sender">
//        ///// Sender of the event
//        ///// </param>
//        ///// <param name="args">
//        ///// Event argument
//        ///// </param>
//        //private void dragMoveArea_MouseLeftButtonDown(object sender, MouseButtonEventArgs args)
//        //{
//        //    if (args.ClickCount == 2)
//        //    {
//        //        // -->> ISSUE #0002
//        //        // Description: Problem while maximizing a window by double click which is positioned almost at top
//        //        // Steps to reproduce:
//        //        // (1) Move window almost to the top of the screen
//        //        // (2) Maximize the window by double click
//        //        // Resulting problem: This "MouseMove" event will be raised (not because the mouse is moved but
//        //        //                    because the window is moved relative to the mouse. And a mouse move event
//        //        //                    in the drag move area while a window is maximized and the left mouse button
//        //        //                    is pressed will raise the aero-unsap implementation (aero unsnap is
//        //        //                    implemented in that way in this class; maybe a better solution can be found)
//        //        // Solution: remove mouse move handler temporary (if necessary)
//        //        IntPtr monitor = DLLIMPORTS.MonitorFromWindow(new WindowInteropHelper(this).Handle, DEFINES.MONITOR_DEFAULTTONEAREST);
//        //        if (monitor != IntPtr.Zero)
//        //        {
//        //            MONITORINFO monitorInfo = new MONITORINFO();
//        //            if (DLLIMPORTS.GetMonitorInfo(monitor, monitorInfo))
//        //            {
//        //                HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
//        //                Matrix matrix = source.CompositionTarget.TransformFromDevice;
//        //                Point dpiIndependentSize = matrix.Transform(new Point(monitorInfo.rcWork.left, monitorInfo.rcWork.top));
//        //                if (Left != dpiIndependentSize.X || Top != dpiIndependentSize.Y)
//        //                {
//        //                    MouseEventHandler handler = null;
//        //                    handler = new MouseEventHandler((object s, MouseEventArgs a) =>
//        //                    {
//        //                        _dragMoveArea.MouseMove -= handler;
//        //                        _dragMoveArea.MouseMove += dragMoveArea_MouseMove;
//        //                    });
//        //                    _dragMoveArea.MouseMove -= dragMoveArea_MouseMove;
//        //                    _dragMoveArea.MouseMove += handler;
//        //                }
//        //            }
//        //        }
//        //        // <<-- ISSUE
//        //        WindowState = (WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized);
//        //        args.Handled = true;
//        //        return;
//        //    }
//        //    if (args.LeftButton == MouseButtonState.Pressed)
//        //    {
//        //        //DragMove();
//        //        args.Handled = true;
//        //        return;
//        //    }
//        //}

//        ///// <summary>
//        ///// Handles the "MouseMove" event of the drag move area
//        ///// </summary>
//        ///// <param name="sender">
//        ///// Sender of the event
//        ///// </param>
//        ///// <param name="args">
//        ///// Event argument
//        ///// </param>
//        //private void dragMoveArea_MouseMove(object sender, MouseEventArgs args)
//        //{
//        //    if (WindowState == WindowState.Maximized)
//        //    {
//        //        if (args.LeftButton == MouseButtonState.Pressed)
//        //        {
//        //            double newTop = 0d;
//        //            IntPtr monitor = DLLIMPORTS.MonitorFromWindow(new WindowInteropHelper(this).Handle, DEFINES.MONITOR_DEFAULTTONEAREST);
//        //            if (monitor != IntPtr.Zero)
//        //            {
//        //                MONITORINFO monitorInfo = new MONITORINFO();
//        //                if (DLLIMPORTS.GetMonitorInfo(monitor, monitorInfo))
//        //                {
//        //                    double restoreWidth = RestoreBounds.Width;
//        //                    Point mousePoint = Mouse.GetPosition(this as IInputElement);
//        //                    HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
//        //                    Matrix matrix = source.CompositionTarget.TransformFromDevice;
//        //                    Point dpiIndependentSize = matrix.Transform(new Point(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.right));
//        //                    Left = dpiIndependentSize.X + mousePoint.X - (restoreWidth / 2d);
//        //                    if (monitorInfo.rcMonitor.left == 0)
//        //                    {
//        //                        Left = Math.Max(0, Left);
//        //                    }
//        //                    if (dpiIndependentSize.Y == SystemParameters.VirtualScreenWidth)
//        //                    {
//        //                        Left = Math.Min(dpiIndependentSize.Y - restoreWidth, Left);
//        //                    }
//        //                    dpiIndependentSize = matrix.Transform(new Point(Math.Abs(monitorInfo.rcWork.left - monitorInfo.rcMonitor.left), Math.Abs(monitorInfo.rcWork.top - monitorInfo.rcMonitor.top)));
//        //                    newTop = dpiIndependentSize.Y;
//        //                }
//        //            }
//        //            Top = newTop;
//        //            _restoreTop = Top;
//        //            _restoreLeft = Left;
//        //            WindowState = WindowState.Normal;
//        //            // -->> ISSUE #0001
//        //            // Description: Wrong top position when using the aero-unspan the first time (sometimes)
//        //            // Steps to reproduce:
//        //            // (1) start the application and maximize the window without any other action / movement
//        //            // (2) use the aero-unsnap to resize the window
//        //            // Resulting problem: The window TOP is restored not to the Top value as set above
//        //            // Solution: Set the window top position again
//        //            Top = newTop;
//        //            // <<-- ISSUE
//        //            MouseButtonEventHandler handler = null;
//        //            handler = new MouseButtonEventHandler((object s, MouseButtonEventArgs a) =>
//        //            {
//        //                Mouse.OverrideCursor = null;
//        //                PreviewMouseLeftButtonUp -= handler;
//        //            });
//        //            PreviewMouseLeftButtonUp += handler;
//        //            Mouse.OverrideCursor = Cursors.Arrow;
//        //            //DragMove();
//        //            args.Handled = true;
//        //        }
//        //    }
//        //}

//        ///// <summary>
//        ///// Handles the "PreviewMouseLeftButtonDown" event of a resize area
//        ///// </summary>
//        ///// <param name="sender">
//        ///// Sender of the event
//        ///// </param>
//        ///// <param name="args">
//        ///// Event argument
//        ///// </param>
//        //private void resizeArea_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
//        //{
//        //    int scSizeDirection = -1;
//        //    scSizeDirection = (sender == _leftResizeArea ? DEFINES.SC_SIZE_HTLEFT : scSizeDirection);
//        //    scSizeDirection = (sender == _leftTopResizeArea ? DEFINES.SC_SIZE_HTTOPLEFT : scSizeDirection);
//        //    scSizeDirection = (sender == _topResizeArea ? DEFINES.SC_SIZE_HTTOP : scSizeDirection);
//        //    scSizeDirection = (sender == _rightTopResizeArea ? DEFINES.SC_SIZE_HTTOPRIGHT : scSizeDirection);
//        //    scSizeDirection = (sender == _rightResizeArea ? DEFINES.SC_SIZE_HTRIGHT : scSizeDirection);
//        //    scSizeDirection = (sender == _rightBottomResizeArea ? DEFINES.SC_SIZE_HTBOTTOMRIGHT : scSizeDirection);
//        //    scSizeDirection = (sender == _bottomResizeArea ? DEFINES.SC_SIZE_HTBOTTOM : scSizeDirection);
//        //    scSizeDirection = (sender == _leftBottomResizeArea ? DEFINES.SC_SIZE_HTBOTTOMLEFT : scSizeDirection);
//        //    if (scSizeDirection != -1)
//        //    {
//        //        Mouse.OverrideCursor = (sender is FrameworkElement ? (sender as FrameworkElement).Cursor : null);
//        //        DLLIMPORTS.SendMessage(HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).Handle, DEFINES.WM_SYSCOMMAND, (IntPtr)(DEFINES.SC_SIZE + scSizeDirection), IntPtr.Zero);
//        //        Mouse.OverrideCursor = null;
//        //    }
//        //}

//        /// <summary>
//        /// Ensures the max screen size settings
//        /// </summary>
//        private void ensureMaxScreenSizeSetting()
//        {
//            _userDefinedMaxHeight = MaxHeight;
//            _userDefinedMaxWidth = MaxWidth;
//            DependencyPropertyDescriptor windowStateDescriptor = DependencyPropertyDescriptor.FromProperty(Window.WindowStateProperty, typeof(CustomWindow));
//            if (windowStateDescriptor != null)
//            {
//                windowStateDescriptor.AddValueChanged(this, (object sender, EventArgs args) =>
//                {
//                    if (WindowState == WindowState.Maximized)
//                    {
//                        double userDefinedMaxHeight = _userDefinedMaxHeight;
//                        MaxHeight = Math.Min(userDefinedMaxHeight, _calculatedMaxHeight);
//                        _userDefinedMaxHeight = userDefinedMaxHeight;
//                        double userDefinedMaxWidth = _userDefinedMaxWidth;
//                        MaxWidth = Math.Min(userDefinedMaxWidth, _calculatedMaxWidth);
//                        _userDefinedMaxWidth = userDefinedMaxWidth;
//                    }
//                    else
//                    {
//                        MaxHeight = _userDefinedMaxHeight;
//                        MaxWidth = _userDefinedMaxWidth;
//                    }
//                });
//            }
//            DependencyPropertyDescriptor maxHeightDescriptor = DependencyPropertyDescriptor.FromProperty(Window.MaxHeightProperty, typeof(CustomWindow));
//            if (maxHeightDescriptor != null)
//            {
//                maxHeightDescriptor.AddValueChanged(this, (object sender, EventArgs args) =>
//                {
//                    _userDefinedMaxHeight = MaxHeight;
//                    if (WindowState == WindowState.Maximized)
//                    {
//                        double userDefinedMaxHeight = _userDefinedMaxHeight;
//                        MaxHeight = Math.Min(userDefinedMaxHeight, _calculatedMaxHeight);
//                        _userDefinedMaxHeight = userDefinedMaxHeight;
//                    }
//                });
//            }
//            DependencyPropertyDescriptor maxWidthDescriptor = DependencyPropertyDescriptor.FromProperty(Window.MaxWidthProperty, typeof(CustomWindow));
//            if (maxWidthDescriptor != null)
//            {
//                maxWidthDescriptor.AddValueChanged(this, (object sender, EventArgs args) =>
//                {
//                    _userDefinedMaxWidth = MaxWidth;
//                    if (WindowState == WindowState.Maximized)
//                    {
//                        double userDefinedMaxWidth = _userDefinedMaxWidth;
//                        MaxWidth = Math.Min(userDefinedMaxWidth, _calculatedMaxWidth);
//                        _userDefinedMaxWidth = userDefinedMaxWidth;
//                    }
//                });
//            }
//        }

//        /// <summary>
//        /// Ensures the maximize monitor
//        /// </summary>
//        private void ensureMaximizedMonitor()
//        {
//            DependencyPropertyDescriptor windowStateDescriptor = DependencyPropertyDescriptor.FromProperty(Window.WindowStateProperty, typeof(CustomWindow));
//            EventHandler handler = null;
//            handler = new EventHandler((object sender, EventArgs args) =>
//            {
//                if (WindowState != WindowState.Maximized)
//                {
//                    Left = _restoreLeft;
//                    Top = _restoreTop;
//                    windowStateDescriptor.RemoveValueChanged(this, handler);
//                }
//            });
//            SizeChanged += new SizeChangedEventHandler((object sender, SizeChangedEventArgs args) =>
//            {
//                if (WindowState == WindowState.Maximized)
//                {
//                    IntPtr windowMonitor = DLLIMPORTS.MonitorFromWindow(new WindowInteropHelper(this).Handle, DEFINES.MONITOR_DEFAULTTONEAREST);
//                    if (windowMonitor != IntPtr.Zero)
//                    {
//                        MONITORINFO windowMonitorInfo = new MONITORINFO();
//                        if (DLLIMPORTS.GetMonitorInfo(windowMonitor, windowMonitorInfo))
//                        {
//                            HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
//                            Matrix matrix = source.CompositionTarget.TransformFromDevice;
//                            Point dpiIndependentSize = matrix.Transform(new Point((windowMonitorInfo.rcWork.right - windowMonitorInfo.rcWork.left), (windowMonitorInfo.rcWork.bottom - windowMonitorInfo.rcWork.top)));
//                            double diffX = ActualWidth - dpiIndependentSize.X;
//                            double diffY = ActualHeight - dpiIndependentSize.Y;
//                            double autoHideTaskbarOffset = 1;
//                            if (Math.Abs(diffX) > autoHideTaskbarOffset || Math.Abs(diffY) > autoHideTaskbarOffset)
//                            {
//                                double opacity = Opacity;
//                                dpiIndependentSize = matrix.Transform(new Point(windowMonitorInfo.rcWork.left, windowMonitorInfo.rcWork.top));
//                                Opacity = 0.75;
//                                WindowState = WindowState.Normal;
//                                _restoreLeft = Left;
//                                _restoreTop = Top;
//                                Left = dpiIndependentSize.X;
//                                Top = dpiIndependentSize.Y;
//                                WindowState = WindowState.Maximized;
//                                if (windowStateDescriptor != null)
//                                {
//                                    windowStateDescriptor.AddValueChanged(this, handler);
//                                }
//                                Opacity = opacity;
//                            }
//                        }
//                    }
//                }
//            });
//        }

//        private int _counter;
//        /// <summary>
//        /// Handles window proc calls
//        /// </summary>
//        /// <param name="hwnd">
//        /// A handle to the window
//        /// </param>
//        /// <param name="uMsg">
//        /// The message
//        /// </param>
//        /// <param name="wParam">
//        /// Additional message information. The contents of this parameter
//        /// depend on the value of the uMsg parameter
//        /// </param>
//        /// <param name="lParam">
//        /// Additional message information. The contents of this parameter
//        /// depend on the value of the uMsg parameter
//        /// </param>
//        /// <param name="handled">
//        /// Flag indicating whether the window proc call was handled
//        /// </param>
//        /// <returns>
//        /// The return value is the result of the message processing and depends
//        /// on the message sent
//        /// </returns>
//        private IntPtr windowProc(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr lParam, ref bool handled)
//        {
//            if (uMsg != 13)
//            {
//                if (_counter++ < 100)
//                {
//                    Tag += uMsg + " | ";
//                }
//                else
//                {
//                    _counter = 0;
//                    Tag = uMsg + " | ";
//                }
//            }
//            switch (uMsg)
//            {
//                case 0x00A0:
//                    //if (wParam.ToInt64() == DEFINES.HTCLOSE)
//                    //{
//                    //    _closeButton.CaptureMouse();
//                    //}
//                    break;
//                case DEFINES.WM_GETMINMAXINFO:
//                    wmGetMinMaxInfo(hwnd, lParam);
//                    handled = true;
//                    break;
//                case 0x0046:
//                    WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
//                    if ((pos.flags & (int)(0x0002)) != 0)
//                    {
//                        return IntPtr.Zero;
//                    }
//                    Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
//                    if (wnd == null)
//                    {
//                        return IntPtr.Zero;
//                    }
//                    bool changedPos = false;
//                    if (pos.cx * 0.8 < MinWidth) { pos.cx = (int)Math.Round(MinWidth / 0.8); changedPos = true; }
//                    if (pos.cy * 0.8 < MinHeight) { pos.cy = (int)Math.Round(MinHeight / 0.8); changedPos = true; }
//                    if (!changedPos)
//                    {
//                        return IntPtr.Zero;
//                    }
//                    Marshal.StructureToPtr(pos, lParam, true);
//                    handled = true;
//                    break;
//                case DEFINES.WM_NCHITTEST:
//                    //Tag = "???";
//                    int x = (short)(lParam.ToInt32() & 0x0000FFFF);
//                    int y = (short)((lParam.ToInt32() & 0xFFFF0000) >> 16);
//                    Point point = PointFromScreen(new Point(x, y));
//                    if (isInside(point, _dragMoveArea))
//                    {
//                        //Tag = "drag move area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTCAPTION;
//                    }
//                    else if (isInside(point, _leftResizeArea))
//                    {
//                        //Tag = "left resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTLEFT;
//                    }
//                    else if (isInside(point, _leftTopResizeArea))
//                    {
//                        //Tag = "left top resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTTOPLEFT;
//                    }
//                    else if (isInside(point, _topResizeArea))
//                    {
//                        Tag = "top resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTTOP;
//                    }
//                    else if (isInside(point, _rightTopResizeArea))
//                    {
//                        //Tag = "right top resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTTOPRIGHT;
//                    }
//                    else if (isInside(point, _rightResizeArea))
//                    {
//                        //Tag = "right resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTRIGHT;
//                    }
//                    else if (isInside(point, _rightBottomResizeArea))
//                    {
//                        //Tag = "right bottom resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTBOTTOMRIGHT;
//                    }
//                    else if (isInside(point, _bottomResizeArea))
//                    {
//                        //Tag = "bottom resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTBOTTOM;
//                    }
//                    else if (isInside(point, _leftBottomResizeArea))
//                    {
//                        //Tag = "left bottom resize area";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTBOTTOMLEFT;
//                    }
//                    else if (isInside(point, _closeButton))
//                    {
//                        object o = Mouse.Captured;
//                        if (o != null)
//                        {
//                        }
//                        //Tag = "close button";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTCLOSE;
//                    }
//                    else if (isInside(point, _maximizeButton))
//                    {
//                        //Tag = "maximize button";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTMAXBUTTON;
//                    }
//                    else if (isInside(point, _minimizeButton))
//                    {
//                        //Tag = "minimize button";
//                        handled = true;
//                        return (IntPtr)DEFINES.HTMINBUTTON;
//                    }
//                    break;
//                    //return DefWindowProc(hwnd, uMsg, wParam, lParam);
//            }
//            return (IntPtr)0;
//        }
//        [DllImport("user32.dll", SetLastError = true)]
//        static extern int GetWindowLong(IntPtr hWnd, int nIndex);
//        [DllImport("user32.dll")]
//        static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
//        [DllImport("user32.dll", CharSet = CharSet.Auto)]
//        public static extern IntPtr DefWindowProc(
//            IntPtr hWnd,
//            int msg,
//            IntPtr wParam,
//            IntPtr lParam);
//        [StructLayout(LayoutKind.Sequential)]
//        internal struct WINDOWPOS
//        {
//            public IntPtr hwnd;
//            public IntPtr hwndInsertAfter;
//            public int x;
//            public int y;
//            public int cx;
//            public int cy;
//            public int flags;
//        }
//        [DllImport("dwmapi.dll")]
//        public static extern IntPtr DwmIsCompositionEnabled(out bool pfEnabled);
//        [DllImport("dwmapi.dll")]
//        public static extern int DwmDefWindowProc(IntPtr hwnd, ushort msg, long wParam, long lParam, out int plResult);

//        /// <summary>
//        /// Checks whether the given point is inside of the given ui element
//        /// </summary>
//        /// <param name="point">
//        /// Point
//        /// </param>
//        /// <param name="uiElement">
//        /// UI element
//        /// </param>
//        /// <returns>
//        /// True if the point is inside of the given ui element, false otherwise
//        /// </returns>
//        private bool isInside(Point point, UIElement uiElement)
//        {
//            if (uiElement == null)
//            {
//                return false;
//            }
//            Point uiElementCorner = uiElement.TransformToAncestor(this).Transform(new Point(0d, 0d));
//            return (uiElementCorner.X <= point.X && point.X <= (uiElementCorner.X + uiElement.RenderSize.Width) &&
//                uiElementCorner.Y <= point.Y && point.Y <= (uiElementCorner.Y + uiElement.RenderSize.Height));
//        }


//        /// <summary>
//        /// Gets the min max info for the window manager
//        /// </summary>
//        /// <param name="hwnd">
//        /// A handle to the window
//        /// </param>
//        /// <param name="lParam">
//        /// Additional message information. The contents of this parameter
//        /// depend on the value of the uMsg parameter
//        /// </param>
//        private void wmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
//        {
//            MINMAXINFO minMaxInfo = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
//            IntPtr windowMonitor = DLLIMPORTS.MonitorFromWindow(hwnd, DEFINES.MONITOR_DEFAULTTONEAREST);
//            if (windowMonitor != IntPtr.Zero)
//            {
//                MONITORINFO windowMonitorInfo = new MONITORINFO();
//                if (DLLIMPORTS.GetMonitorInfo(windowMonitor, windowMonitorInfo))
//                {
//                    minMaxInfo.ptMaxPosition.x = Math.Abs(windowMonitorInfo.rcWork.left - windowMonitorInfo.rcMonitor.left);
//                    minMaxInfo.ptMaxPosition.y = Math.Abs(windowMonitorInfo.rcWork.top - windowMonitorInfo.rcMonitor.top);
//                    minMaxInfo.ptMaxSize.x = Math.Abs(windowMonitorInfo.rcWork.right - windowMonitorInfo.rcWork.left);
//                    minMaxInfo.ptMaxSize.y = Math.Abs(windowMonitorInfo.rcWork.bottom - windowMonitorInfo.rcWork.top);
//                    // -->> ISSUE #0003 (Part 2)
//                    // Description: Wrong window size in monitor 2 if monitor 2 is bigger than monitor 1
//                    // Steps to reproduce:
//                    // (1) Attach a second monitor
//                    // (2) Set screen resolution of monitor 2 to a bigger value than for monitor 1
//                    // (3) Maximize the window in monitor 2
//                    // Resulting problem: Maximized window has the wrong size (the window is too big)
//                    // Solution: Use MaxHeight and MaxWidth and limit the window size by that values (but
//                    //           use those values only if the window is maximized and then use the minimum
//                    //           of the values calculated during the getminmaxinfo method and the user
//                    //           defined values)
//                    HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
//                    Matrix matrix = source.CompositionTarget.TransformFromDevice;
//                    Point dpiIndependentSize = matrix.Transform(new Point(minMaxInfo.ptMaxSize.x, minMaxInfo.ptMaxSize.y));
//                    _calculatedMaxHeight = dpiIndependentSize.Y;
//                    _calculatedMaxWidth = dpiIndependentSize.X;
//                    // <<-- ISSUE
//                    if (isTaskBarAutoHideFlagSet() == true)
//                    {
//                        switch (getTaskBarPosition())
//                        {
//                            case DEFINES.ABE_LEFT:
//                                minMaxInfo.ptMaxPosition.x += 1;
//                                minMaxInfo.ptMaxSize.x -= 1;
//                                break;
//                            case DEFINES.ABE_TOP:
//                                minMaxInfo.ptMaxPosition.y += 1;
//                                minMaxInfo.ptMaxSize.y -= 1;
//                                break;
//                            case DEFINES.ABE_RIGHT:
//                                minMaxInfo.ptMaxSize.x -= 1;
//                                break;
//                            case DEFINES.ABE_BOTTOM:
//                                minMaxInfo.ptMaxSize.y -= 1;
//                                break;
//                        }
//                    }
//                }
//            }
//            Marshal.StructureToPtr(minMaxInfo, lParam, true);
//        }

//        /// <summary>
//        /// Gets a flag indicating whether the auto hide flag of the task bar is
//        /// set
//        /// </summary>
//        /// <returns>
//        /// True if the auto hide flag is set for the task bar, null if no task
//        /// bar found, false otherwise
//        /// </returns>
//        private bool? isTaskBarAutoHideFlagSet()
//        {
//            IntPtr taskBarWindow = DLLIMPORTS.FindWindow("Shell_TrayWnd", null);
//            if (taskBarWindow != null)
//            {
//                APPBARDATA appBarData = new APPBARDATA();
//                appBarData.cbSize = Marshal.SizeOf(appBarData);
//                appBarData.hWnd = taskBarWindow;
//                int state = DLLIMPORTS.SHAppBarMessage((int)DEFINES.ABM_GETSTATE, ref appBarData);
//                return ((state & DEFINES.ABS_AUTOHIDE) == DEFINES.ABS_AUTOHIDE);
//            }
//            return null;
//        }

//        /// <summary>
//        /// Gets the task bar position as interger value
//        /// </summary>
//        /// <returns>
//        /// The task bar position as interger value:
//        /// - 0: task bar not found
//        /// - 1: left
//        /// - 2: top
//        /// - 3: right
//        /// - 4: bottom
//        /// </returns>
//        private int getTaskBarPosition()
//        {
//            IntPtr taskBarWindow = DLLIMPORTS.FindWindow("Shell_TrayWnd", null);
//            if (taskBarWindow != null)
//            {
//                APPBARDATA appBarData = new APPBARDATA();
//                appBarData.cbSize = Marshal.SizeOf(appBarData);
//                appBarData.hWnd = taskBarWindow;
//                DLLIMPORTS.SHAppBarMessage((int)DEFINES.ABM_GETTASKBARPOS, ref appBarData);
//                return appBarData.uEdge;
//            }
//            return 0;
//        }

//        /// <summary>
//        /// Gets the task bar bounds
//        /// </summary>
//        /// <returns>
//        /// Task bar bounds (empty if no task bar found)
//        /// </returns>
//        private Rect getTaskBarBounds()
//        {
//            Rect result = new Rect();
//            IntPtr taskBarWindow = DLLIMPORTS.FindWindow("Shell_TrayWnd", null);
//            if (taskBarWindow != null)
//            {
//                APPBARDATA appBarData = new APPBARDATA();
//                appBarData.cbSize = Marshal.SizeOf(appBarData);
//                appBarData.hWnd = taskBarWindow;
//                DLLIMPORTS.SHAppBarMessage((int)DEFINES.ABM_GETTASKBARPOS, ref appBarData);
//                result = new Rect(appBarData.rc.left, appBarData.rc.top, (appBarData.rc.right - appBarData.rc.left), (appBarData.rc.bottom - appBarData.rc.top));
//            }
//            return result;
//        }

//    }

//}
